package net.kesumu.yushabu.testing;

import java.net.URI;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Locale;

import net.kesumu.yushabu.LoginActivity;
import net.kesumu.yushabu.utils.JSONUtil;
import net.kesumu.yushabu.utils.WsConfig;

import com.codebutler.android_websockets.WebSocketClient;
import net.kesumu.yushabu.R;

import android.annotation.SuppressLint;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Messenger;
import android.os.RemoteException;
import android.widget.Toast;

public class ConnectionService extends Service{
    public static final String CONNECTIONSERVICE_TAKEN = "com.kesumu.yushabu.ConnectionService";
    private WebSocketClient client;
    private JSONUtil jsonUtil;
    
    int currentClientIndex = -1;
    
    /** For showing and hiding our notification. */
    NotificationManager mNM;


    /** Keeps track of all current registered clients. */
    ArrayList<Messenger> mClients = new ArrayList<Messenger>();
    
    /** Holds last value set by a client. */
    int mValue = 0;

    /**
     * Command to the service to register a client, receiving callbacks
     * from the service.  The Message's replyTo field must be a Messenger of
     * the client where callbacks should be sent.
     */
    public static final int MSG_REGISTER_CLIENT = 1;

    /**
     * Command to the service to unregister a client, ot stop receiving callbacks
     * from the service.  The Message's replyTo field must be a Messenger of
     * the client as previously given with MSG_REGISTER_CLIENT.
     */
    public static final int MSG_UNREGISTER_CLIENT = 2;

    /**
     * Command to service to set a new value.  This can be sent to the
     * service to supply a new value, and will be sent by the service to
     * any registered clients with the new value.
     */
    public static final int MSG_MESSAGE = 3;

    /**
     * Handler of incoming messages from clients.
     */
    @SuppressLint("HandlerLeak")
    class IncomingHandler extends Handler {
        public void handleMessage(android.os.Message msg) {
            switch (msg.what) {
                case MSG_REGISTER_CLIENT:
                    mClients.add(msg.replyTo);
                    currentClientIndex = mClients.size()-1;
                    break;
                case MSG_UNREGISTER_CLIENT:
                    mClients.remove(msg.replyTo);
                    break;
                case MSG_MESSAGE:
                    String message = msg.getData().getString("message");
                    sendMessageToServer(message);
                    break;
                default:
                    super.handleMessage(msg);
            }
        }
    }

    /**
     * Target we publish for clients to send messages to IncomingHandler.
     */
    final Messenger mMessenger = new Messenger(new IncomingHandler());

    @Override
    public void onCreate() {
        super.onCreate();
        
        mNM = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);

        // Display a notification about us starting.
        showNotification();

        
        jsonUtil = new JSONUtil(getApplicationContext());
        
        /**
         * Creating web socket client. This will have callback methods
         * */
        client = new WebSocketClient(URI.create(WsConfig.URL_WEBSOCKET
                + URLEncoder.encode("Guest")), new WebSocketClient.Listener() {
            public void onConnect() {
                
            }
            /**
             * On receiving the message from web socket server
             * */
            public void onMessage(String message) {
                sendMessageBackToClient(message);
            }
            public void onMessage(byte[] data) {
                // Message will be in JSON format
                sendMessageBackToClient(bytesToHex(data));
            }
            /**
             * Called when the connection is terminated
             * */
            public void onDisconnect(int code, String reason) {
                String message = String.format(Locale.US,
                        "Disconnected! Code: %d Reason: %s", code, reason);
                showToast(message);
            }
            public void onError(Exception error) {
                showToast("Error! : " + error);
            }
        }, null);
        client.connect();
    }
    
    @Override
    public void onDestroy() {
        super.onDestroy();
        // Cancel the persistent notification.
        mNM.cancel(R.string.title);
    }
    
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        super.onStartCommand(intent, flags, startId);
        return Service.START_STICKY;
    }
    
    @Override
    public IBinder onBind(Intent intent) {
        return mMessenger.getBinder();
    }

    /**
     * Show a notification while this service is running.
     */
    private void showNotification() {
        // In this sample, we'll use the same text for the ticker and the expanded notification
        CharSequence text = getText(R.string.title);

        // Set the icon, scrolling text and timestamp
        Notification notification = new Notification(R.drawable.chara_fuu_face, text,
                System.currentTimeMillis());

        // The PendingIntent to launch our activity if the user selects this notification
        PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
                new Intent(this, LoginActivity.class), 0);

        // Set the info for the views that show in the notification panel.
        notification.setLatestEventInfo(this, getText(R.string.title),
                       text, contentIntent);

        // Send the notification.
        // We use a string id because it is a unique number.  We use it later to cancel.
        mNM.notify(R.string.title, notification);
    }

    
    //custom functions
    /**
     * Method to send message to web socket server
     * */
    private void sendMessageToServer(String message) {
        if (client != null && client.isConnected()) {
            client.send(message);
        }
    }
    
    private void sendMessageBackToClient(String message) {
        try {
            android.os.Message msg = android.os.Message.obtain(null,MSG_MESSAGE, 0, 0);
            Bundle buddleOfData = new Bundle();
            buddleOfData.putString("message", message);
            msg.setData(buddleOfData);
            mClients.get(currentClientIndex).send(msg);
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }
    
    final protected static char[] hexArray = "0123456789ABCDEF".toCharArray();
    public static String bytesToHex(byte[] bytes) {
        char[] hexChars = new char[bytes.length * 2];
        for (int j = 0; j < bytes.length; j++) {
            int v = bytes[j] & 0xFF;
            hexChars[j * 2] = hexArray[v >>> 4];
            hexChars[j * 2 + 1] = hexArray[v & 0x0F];
        }
        return new String(hexChars);
    }
    
    private void showToast(final String message) {
        Toast.makeText(getApplicationContext(), message,
                        Toast.LENGTH_LONG).show();
    }
}
